package com.ssy.lingxi.report.serviceimpl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONUtil;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.report.api.enums.CommonBooleanEnum;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeAddVO;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeVO;
import com.ssy.lingxi.report.constant.Constants;
import com.ssy.lingxi.report.entity.report.MemberTallyReportDO;
import com.ssy.lingxi.report.model.vo.response.*;
import com.ssy.lingxi.report.service.*;
import com.ssy.lingxi.report.service.tally.ITallyReportService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 会员首页接口定义实现
 * @author 伍将
 * @date 2020/11/17
 * @version 2.0.0
 */
@Service
public class MemberHomeServiceImpl implements IMemberHomeService {

    private static final Logger logger = LoggerFactory.getLogger(MemberHomeServiceImpl.class);


    @Resource
    private ITallyReportService tallyReportService;
    @Resource
    private INewlyAddedDayReportService newlyAddedDayReportService;
    @Resource
    private IAppBacklogNoticeService appBacklogNoticeService;
    @Resource
    private IMemberReportService memberReportService;
    @Resource
    private IFeignService feignService;

    //首字母转大写
    public String upperFirstLatter(String str){
        return str.substring(0, 1).toUpperCase()+str.substring(1);
    }

    /**
     * 根据用户权限过滤用户首页-待办数
     * @param obj 用户
     * @param webLimitUrlListByUserId 按用户 ID 限制网址列表
     */
    private void filterLimitUrl(Object obj,List<String> webLimitUrlListByUserId){
        Field[] fields = ReflectUtil.getFields(obj.getClass());
        Set<String> methodNames = ReflectUtil.getMethodNames(obj.getClass()).stream()
                                    .filter(o ->o.startsWith(Constants.GET)||o.startsWith(Constants.SET)).collect(Collectors.toSet());
        boolean limits = webLimitUrlListByUserId != null;
        for (Field o : fields) {
            Type type = o.getGenericType();
            if (type instanceof ParameterizedType) {
                ParameterizedType ptype = (ParameterizedType) type;
                if (ptype.getRawType() == List.class) {
                    if (ptype.getActualTypeArguments().length == 1
                            && ptype.getActualTypeArguments()[0] == TallyReportItemVO.class) {
                        String fieldName = upperFirstLatter(o.getName());
                        String methodName = Constants.GET + fieldName;
                        if (methodNames.contains(methodName)) {
                            Object invoke = ReflectUtil.invoke(obj, methodName);
                            List<TallyReportItemVO> list;
                            if (invoke != null && limits) {
                                list = (List<TallyReportItemVO>) invoke;
                                list = list.stream().filter(v -> webLimitUrlListByUserId.contains(v.getLink())).collect(Collectors.toList());
                                methodName = Constants.SET + fieldName;
                                ReflectUtil.invoke(obj, methodName, Optional.ofNullable(list).orElse(new ArrayList<>()));
                            }
                        } else {
                            logger.info("MemberHomeServiceImpl->filterLimitUrl:Class:{},属性{}没有set,get方法", obj.getClass(), o.getName());
                        }
                    }
                }
            }
        }
    }

    /**
     * 获取交易中心报表
     * @param user 登录用户
     * @return 交易中心报表
     */
    @Override
    public Wrapper<TradeTallyReportVO> getTradeReport(UserLoginCacheDTO user) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(user.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(user);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        TradeTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getTrade();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }
        return Wrapper.success(result);
    }

    /**
     * 获取资金账户管理中心报表
     * @param user 登录用户
     * @return 资金账户管理中心报表
     */
    @Override
    public Wrapper<AccountTallyReportVO> getAccount(UserLoginCacheDTO user) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(user.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(user);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        AccountTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getAccount();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }

        return Wrapper.success(result);
    }

    /**
     * 获取结算中心报表
     * @param user 登录用户
     * @return 结算中心报表
     */
    @Override
    public Wrapper<SettleAccountTallyReportVO> getSettleAccountReport(UserLoginCacheDTO user) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(user.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(user);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        SettleAccountTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getSettleAccount();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }

        return Wrapper.success(result);
    }

    /**
     * 获取售后中心报表
     * @param user 登录用户
     * @return 售后中心报表
     */
    @Override
    public Wrapper<AfterSaleTallyReportVO> getAfterSaleReport(UserLoginCacheDTO user) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(user.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(user);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        AfterSaleTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getAfterSale();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }
        return Wrapper.success(result);
    }

    /**
     * 获取加工中心报表
     * @param user 登录中心
     * @return 加工中心报表
     */
    @Override
    public Wrapper<EnhanceTallyReportVO> getEnhanceReport(UserLoginCacheDTO user) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(user.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(user);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        EnhanceTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getEnhance();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }

        return Wrapper.success(result);
    }

    /**
     * 获取商品中心报表
     * @param user 登录用户
     * @return 商品中心报表
     */
    @Override
    public Wrapper<List<TallyReportItemVO>> getCommodityReport(UserLoginCacheDTO user) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(user.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(user);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        CommodityTallyReportVO result = null;
        if (wrapper.getData() != null && wrapper.getData().getCommodity() != null) {
            result = wrapper.getData().getCommodity();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }

        return Wrapper.success(result!=null?result.getTallyList():null);
    }

    /**
     * 获取物流中心报表
     * @param user 登录用户
     * @return 物流中心报表
     */
    @Override
    public Wrapper<LogisticsTallyReportVO> getLogisticsReport(UserLoginCacheDTO user) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(user.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(user);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        LogisticsTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getLogistics();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }

        return Wrapper.success(result);
    }

    /**
     * 批量新增操作通知
     * @param operateVOList 操作数据列表
     * @return 结果
     */
    @Override
    @Transactional
    public Wrapper<Void> addOperateNoticeList(List<OperateNoticeVO> operateVOList) {

        for (OperateNoticeVO operateVO : operateVOList) {
            if (operateVO == null) continue;
            if (operateVO.getIncreaseCount() <= 0 && operateVO.getReduceCount() <= 0) continue;

            handOperateNotice(operateVO);
        }

        return Wrapper.success();
    }

    /**
     * 新增操作通知
     * @param operateVO 操作数据
     * @return 操作结果
     */
    @Override
    @Transactional
    public Wrapper<Void> addOperateNotice(OperateNoticeVO operateVO) {
        // 处理操作通知
        handOperateNotice(operateVO);

        return Wrapper.success();
    }
    /**
     * 新增操作通知
     * @param operateVO 操作数据
     */
    @Override
    @Transactional
    public void addOperateNotice(OperateNoticeAddVO operateVO) {
        if(operateVO!=null){
            OperateNoticeVO operateNoticeVO = operateVO.getOperateNoticeVO();
            List<OperateNoticeVO> operateNoticeVOList = operateVO.getOperateNoticeVOList();
            if(operateNoticeVO!=null){
                addOperateNotice(operateNoticeVO);
            }else if(CollectionUtil.isNotEmpty(operateNoticeVOList)){
                addOperateNoticeList(operateNoticeVOList);
            }
        }
    }

    /**
     * 处理通知
     * @param operateVO 操作数据
     */
    private void handOperateNotice(OperateNoticeVO operateVO) {
        logger.info("收到通知: {}", JSONUtil.toJsonStr(operateVO));
        try {
            handOperateNotice(operateVO,3);
        }catch (Exception e){
            logger.error("处理操作通知异常,operateVO:{},msg:：",JSONUtil.toJsonStr(operateVO),e);
            throw new BusinessException(ResponseCode.REPORT_HANDLE_SYS_OPERATE_NOTICE_ERROR);
        }
    }

    /**
     * 处理通知
     * @param operateVO 操作数据
     */
    private void handOperateNotice(OperateNoticeVO operateVO,Integer retryNum) {
        try {
            if (operateVO == null) return;
            //设置默认值
            if(operateVO.getReduceCount()==null){
                operateVO.setReduceCount(0L);
            }
            if(operateVO.getIncreaseCount()==null){
                operateVO.setIncreaseCount(0L);
            }
            if (operateVO.getIncreaseCount() <= 0 && operateVO.getReduceCount() <= 0) return;

            // 更新web首页代办计数
            tallyReportService.updateTallyReport(operateVO);

            // 更新App待办通知
            appBacklogNoticeService.updateNotice(operateVO);

            // 更新每日更新
            newlyAddedDayReportService.update(operateVO);

            // 更新会员注册报表
            memberReportService.updateMemberRegisterReport(operateVO);
        }catch(DataIntegrityViolationException e){//唯一约束冲突异常
            logger.info("处理操作通知异常,operateVO:{},retryNum:{}",JSONUtil.toJsonStr(operateVO),retryNum);
            try {
                if(retryNum>0) {
                    Thread.sleep(800);
                    handOperateNotice(operateVO, retryNum--);
                }
            } catch (InterruptedException interruptedException) {
                logger.error("处理操作通知线程异常",interruptedException);
            }
        }

    }



    /**
     * 获取会员代办
     * @author 伍将
     * @date 2020/12/30
     * @param user 当前登录用户
     * @return 代表事项
     **/
    @Override
    public Wrapper<MemberTodoVO> getMemberTodo(UserLoginCacheDTO user) {
        MemberTallyReportDO reportDO = tallyReportService.getDetail(user);

        MemberTodoVO result = new MemberTodoVO();
        if (null != reportDO && null != reportDO.getTallyReport()) {
            if (null != reportDO.getTallyReport().getAfterSaleReplaceApply()) {
                result.setReplaceGoodsApplyCount(reportDO.getTallyReport().getAfterSaleReplaceApply().getTotalCount());
                result.setReplaceGoodsApply(reportDO.getTallyReport().getAfterSaleReplaceApply());
            }
            if (null != reportDO.getTallyReport().getAfterSaleReturnApply()) {
                result.setReturnGoodsApplyCount(reportDO.getTallyReport().getAfterSaleReturnApply().getTotalCount());
                result.setReturnGoodsApply(reportDO.getTallyReport().getAfterSaleReturnApply());
            }
            if (null != reportDO.getTallyReport().getAfterSaleRepairApply()) {
                result.setRepairGoodsApplyCount(reportDO.getTallyReport().getAfterSaleRepairApply().getTotalCount());
                result.setRepairGoodsApply(reportDO.getTallyReport().getAfterSaleRepairApply());
            }
            if (null != reportDO.getTallyReport().getTradePurchaseOrder()) {
                result.setPurchaseOrderCount(reportDO.getTallyReport().getTradePurchaseOrder().getTotalCount());
                result.setPurchaseOrder(reportDO.getTallyReport().getTradePurchaseOrder());
            }
            if (null != reportDO.getTallyReport().getTradeInquiryQuotation()) {
                result.setInquiryQuotationCount(reportDO.getTallyReport().getTradeInquiryQuotation().getTotalCount());
                result.setInquiryQuotation(reportDO.getTallyReport().getTradeInquiryQuotation());
            }
            if (null != reportDO.getTallyReport().getTradeCommodityInquiry()) {
                result.setCommodityInquiryCount(reportDO.getTallyReport().getTradeCommodityInquiry().getTotalCount());
                result.setCommodityInquiry(reportDO.getTallyReport().getTradeCommodityInquiry());
            }
        }

        return Wrapper.success(result);
    }

    /**
     * 获取会员商城待办
     * @author 伍将
     * @date 2021/1/18
     * @param user: 当前登录用户
     * @param isPurchase: 是否为采购商（0：否，1：是）
     * @return 会员商城待办
     **/
    @Override
    public Wrapper<MemberMallBacklogVO> getMemberMallBacklog(UserLoginCacheDTO user, Integer isPurchase) {

        MemberMallBacklogVO result = new MemberMallBacklogVO();

        MemberTallyReportDO reportDO = tallyReportService.getDetail(user);
        if (null != reportDO && null != reportDO.getTallyReport()) {

            // 采购待办
            if (CommonBooleanEnum.YES.getCode().equals(isPurchase)) {
                if (null != reportDO.getTallyReport().getTradePurchaseOrder()) {
                    result.setPurchaseToBeValify(reportDO.getTallyReport().getTradePurchaseOrder().getToBeValifyStep1Count());
                    result.setPurchaseToBePay(reportDO.getTallyReport().getTradePurchaseOrder().getToBePayCount());
                    result.setPurchaseToBeReceive(reportDO.getTallyReport().getTradePurchaseOrder().getToBeConfirmReceiveGoodsCount());
                    result.setPurchaseToBeArchive(reportDO.getTallyReport().getTradePurchaseOrder().getToBeArchiveCount());
                }
            }
            // 销售待办
            else {
                if (null != reportDO.getTallyReport().getTradeSaleOrder()) {
                    result.setSaleToBeValify(reportDO.getTallyReport().getTradeSaleOrder().getToBeCommitValifyCount());
                    result.setSaleToBeConfirm(reportDO.getTallyReport().getTradeSaleOrder().getToBeConfirmCount());
                    result.setSaleToBeDelivery(reportDO.getTallyReport().getTradeSaleOrder().getToBeAddDeliveryGoodsCount());
                    result.setSaleToBeArchive(reportDO.getTallyReport().getTradeSaleOrder().getToBeArchiveCount());
                }
            }
        }

        return Wrapper.success(result);
    }

    /**
     * 会员中心
     * @param sysUser 登录用户
     * @return 会员中心
     */
    @Override
    public Wrapper<MemberTallyReportVO> getMemberReport(UserLoginCacheDTO sysUser) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(sysUser.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(sysUser);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        MemberTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getMember();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }
        return Wrapper.success(result);
    }

    /**
     * 获取合同中心报表
     * @param user 登录用户
     * @return 合同中心报表
     */
    @Override
    public Wrapper<ContractTallyReportVO> getContractReport(UserLoginCacheDTO user) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(user.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(user);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        ContractTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getContract();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }
        return Wrapper.success(result);
    }

    /**
     * 获取采购中心报表
     * @param sysUser 登录用户
     * @return 采购中心报表
     */
    @Override
    public Wrapper<PurchaseTallyReportVO> getPurchaseReport(UserLoginCacheDTO sysUser) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(sysUser.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(sysUser);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        PurchaseTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getPurchase();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }
        return Wrapper.success(result);
    }

    /**
     * 获取订单中心报表
     * @param sysUser 登录用户
     * @return 订单中心报表
     */
    @Override
    public Wrapper<OrderTallyReportVO> getOrderReport(UserLoginCacheDTO sysUser) {
        List<String> webLimitUrlListByUserId = feignService.getWebLimitUrlListByUserId(sysUser.getUserId());
        if(CollectionUtil.isEmpty(webLimitUrlListByUserId)){
            return Wrapper.success();
        }
        Wrapper<TallyReportVO> wrapper = tallyReportService.getTallyReport(sysUser);
        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
            return Wrapper.fail(wrapper);
        }
        OrderTallyReportVO result = null;
        if (wrapper.getData() != null) {
            result = wrapper.getData().getOrder();
            filterLimitUrl(result,webLimitUrlListByUserId);
        }
        return Wrapper.success(result);
    }
}
